#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016-2017, 2021, Niklas Hauser
# Copyright (c) 2017, Fabian Greif
#
# This file is part of the modm project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# -----------------------------------------------------------------------------

class FreeRTOS_TCP_LAN8720A(Module):
    def init(self, module):
        module.name = "lan8720a"
        module.description = """
# a:FreeRTOS-Plus-TCP Ethernet via LAN8720A

This module implements TCP over Ethernet via the LAN8720A transceiver.
"""
    def prepare(self, module, options):
        device = options[":target"]
        if not device.has_driver("eth:stm32*"):
            return False
        if device.identifier.family not in ["f7", "f4"]:
            return False
        module.depends(":platform:eth", ":driver:lan8720a")
        return True

    def build(self, env):
        env.outbasepath = "modm/ext/freertos_plus_tcp"
        env.copy("modm_lan8720a.cpp")


class FreeRTOS_TCP(Module):
    def init(self, module):
        module.name = "tcp"
        module.description = FileReader("freertos_tcp.md")

    def prepare(self, module, options):
        module.add_submodule(FreeRTOS_TCP_LAN8720A())
        return True

    def build(self, env):
        env.outbasepath = "modm/ext"
        env.substitutions = {"with_debug": env.has_module(":debug")}
        env.copy("freertos/FreeRTOS-Plus-TCP/source", "freertos_plus_tcp", ignore=env.ignore_files("portable"))
        env.copy("freertos/FreeRTOS-Plus-TCP/source/portable/BufferManagement/BufferAllocation_2.c", "freertos_plus_tcp/BufferAllocation_2.c")
        env.copy("freertos/FreeRTOS-Plus-TCP/tools", "freertos_plus_tcp", ignore=env.ignore_files("*.md", "*.cfg"))
        # Copy the compiler support files
        env.copy("freertos/FreeRTOS-Plus-TCP/source/portable/Compiler/GCC/pack_struct_start.h", "freertos_plus_tcp/include/pack_struct_start.h")
        env.copy("freertos/FreeRTOS-Plus-TCP/source/portable/Compiler/GCC/pack_struct_end.h", "freertos_plus_tcp/include/pack_struct_end.h")

        env.collect(":build:path.include", "modm/ext/freertos_plus_tcp/include")
        env.collect(":build:path.include", "modm/ext/freertos_plus_tcp/tcp_utilities/include")
        env.template("FreeRTOSIPConfig.h.in", "freertos_plus_tcp/include/FreeRTOSIPConfig.h")
# -----------------------------------------------------------------------------

def init(module):
    module.name = "freertos"
    module.description = FileReader("freertos.md")

def prepare(module, options):
    device = options[":target"]
    core = device.get_driver("core")
    if not (core and core["type"].startswith("cortex-m")):
        return False

    if "m0" not in core:
        def validate_frequency(freq):
            if (1000 % freq > 1):
                raise ValueError("FreeRTOS frequency must cleanly divide 1kHz for modm::Clock!")
        module.add_option(
            NumericOption(
                name="frequency",
                description="Context switch frequency in Hz",
                validate=validate_frequency,
                minimum=4, maximum=1000,
                default=1000))

    module.depends(
        ":architecture:assert",
        ":cmsis:device",
        ":platform:clock")

    module.add_submodule(FreeRTOS_TCP())

    return True

def build(env):
    # Figure out the core and correct path in portable/
    core = env[":target"].get_driver("core")["type"]
    env.substitutions = {
        "core": core,
        "frequency": env.get("frequency", 1000),
        "with_debug": env.has_module(":debug"),
        "with_heap": env.has_module(":platform:heap"),
        "with_fpu": env.get(":platform:cortex-m:float-abi", "soft") != "soft",
    }
    path = core.replace("cortex-m", "ARM_CM").replace("+", "").replace("fd", "f").upper()
    path = path.replace("CM7F", "CM7/r0p1") # use subfolder for M7
    path = path.replace("CM33F", "CM33") # common port for FPU/non-FPU version
    path = path.replace("CM33", "CM33_NTZ/non_secure") # no trustzone supported, use non_secure subfolder
    path = "freertos/FreeRTOS/Source/portable/GCC/{}".format(path)

    env.outbasepath = "modm/ext"
    # Copy our own modm-specific port
    env.template("modm_port.cpp.in", "freertos/modm_port.cpp")
    # Copy the entire source folder, minus portable folder and some files.
    env.copy("freertos/FreeRTOS/Source", "freertos",
             ignore=env.ignore_files("*.txt", "*.readme", "portable", "include"))
    env.copy("freertos/FreeRTOS/Source/include", "freertos/inc/freertos")
    # Copy the port.c file
    env.copy("{}/port.c".format(path), "freertos/port.c")
    # Copy the portmacro.h file
    env.copy("{}/portmacro.h".format(path), "freertos/inc/freertos/portmacro.h")
    # Copy the portasm.c/.h files for CM33
    if "CM33" in path:
        env.copy("{}/portasm.c".format(path), "freertos/portasm.c")
        env.copy("{}/portasm.h".format(path), "freertos/inc/freertos/portasm.h")
        env.copy("{}/portmacrocommon.h".format(path), "freertos/inc/freertos/portmacrocommon.h")

    # Generate the FreeRTOSConfig.h file
    env.template("FreeRTOSConfig.h.in", "freertos/inc/freertos/FreeRTOSConfig.h")

    env.collect(":build:path.include", "modm/ext/freertos/inc/freertos")
    env.collect(":build:path.include", "modm/ext/freertos/inc")
